﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//一级指针（类型:int）*
//int* p  char* p1  double* p2

//二级指针 （类型:int*）*
/*
int main()
{
	int a = 10;
	int* p = &a;//取出a的地址
	//p是一级指针变量，是一级指针
	//p这个指针变量，也有自己的地址

	int* *pp=&p;//将指针变量的地址也取出
	//pp是二级指针

	//*pp = p;
	//**pp = a;
	printf("%d", **pp);//二级指针进行两次解引用，会得到一级指针指向的数据

	return 0;
}
*/


// 指针数组
//本质：“ 存放地址的数组”（每个元素都是指针类型）
// int arr[10];整型数组
// char ch[5];字符型数组
// 
// 指针型数组:
// int*    arr[10];
// float*  pf[3];

// 指针模拟二维数组的效果
//二维数组的每一行是一个一维数组
/*
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	//数组名表示起始元素的地址:int* 型指针
	int* arr[3] = { arr1,arr2,arr3 };//定义一个整型指针型数组
	//下标为          0    1    2
	//一次放下三个数组
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
			//           *((arr+i)+j)//（（arr数组的首元素+下标）+下标）
			//arr[i]访问arr指针数组内部下标为i的元素：arr[i]=arr1[]
			//再加上[j]访问arr1[]内部的下标为j的元素：arr1[j]
		}
		//arr[0],访问下标为0的元素==访问arr1
		printf("\n");
	}
	return 0;
}
*/








// 深入理解指针（3）
//
// 字符型指针变量：char*(加数减数跳一个字节)
// 
// char ch='w';
// char* pc=&ch;
// 新写法：
// 
// const char* p="abcdef";//p这个指针变量：存入的是起始字符的地址，首元素a
//  //此字符串是常量字符串，加上const可以防止被修改
// 
// 数组名都是首元素的地址
// 
// //是否将字符串abcdef\0都存放在p中？❌
// 而是把起始字符的地址：a
// 存放在了p（指针变量）中
// 
//✔ //可以把字符串想象成一个字符数组，数组存地址，也是只存首元素的地址
//   //此字符串是常量字符串，是不可修改的，加上const可以防止被修改
//   //当常量字符串出现在表达式中的时候，他的值是第一个字符的地址
// 
// printf("%c ","abcdef"[3]);
//  printf("%c ",p[3]);
// //也可以像数组一样加[下标]来访问下标为n的字符















// 指针型 数组变量
//本质：“ 存放地址的数组”（每个元素都是指针类型）
// int arr[10];整型数组
// char ch[5];字符型数组
// 
// 指针型数组:
// int*    arr[10];
// float*  pf[3];




//数组型 指针变量：
// 存放数组地址的指针
// int* p 整型指针
// foat* pl 浮点型指针
// 
// 字符指针变量：存放字符的地址
// 数组指针变量：存放数组地址
/*
int main()
{
	int n = 100;
	int* pn = &n;

	char ch = 'w';
	char* pc = &pc;

	float f = 3.14f;
	float* pf = &f;

	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*parr)[10] = &arr;//取出数组的地址parr
	//*parr：解引用，int型元素【10】个
	//parr是数组指针
	
	 //int(*p2)[10];//p2是指针，指针指向的是数组，数组有10个元素，元素都是int型
	return 0;
}
*/



// int* p1=arr;
// int* p2=&arr[0];
// 
// int (*p3)[10]=&arr;//数组指针
// 初始化：
// int (*) []=&arr


//
/*
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int(* p)[10] = &arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	//for (i = 0; i < sz; i++)
	//{
	//	printf("%d ", *(p + i));
	// 
	// //输出改成（*p）[i]才能在循环里使用
	//}
	
	//若使用数组指针，+-一个数，相当于跳过一整个数组
	// （因为数组指针，指向的是整个数组，而不是首元素）

	return 0;
}
*/

//二维数组传参的本质
//
//二维数组是由一维数组为元素构成的
// 二维数组的数组名：首元素（首数组）的地址：第一行的地址
// 
//形参可以是数组
//形参也可以是指针
/*
void print(int (*arr)[5], int r, int c)
//             首行（元素）地址
//            *arr 解引用一个二维数组：得到每一行  [5]每一行有五个元素
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", *(*(arr+i)+j));
			//    内层：*（arr+i）：首元素（第一行）地址加数：得到每一行的地址（再解引用）
			//    外层：*（内层+j）：每一行首元素（每一行的第一列）的地址加数：得到每行每列的地址（再解引用）
			
		}
		printf("\n");
	}

}

int main()
{
	int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
	   //三个数组元素，一个数组元素里有五个元素
	print(arr, 3, 5);
	//arr传的是第一个元素：第一个一维数组的地址
}
*/




//函数指针变量
int Add(int x, int y)
{
	return x + y;
}

int main()
{
	//int a = 10;
	//int* pa = &a;

	//int arr[10] = { 0 };
	//int(*parr)[10] = &arr;

	//函数指针是用来存放函数的地址的
	printf("%p\n", &Add);
	printf("%p\n", Add);
	//数组名：首元素地址
	//&数组名：整个数组的地址

    //函数名：函数的地址
	// int (*pf)(int,int) = Add;
	//&函数名：函数的地址
	int (*pf)(int,int) = &Add;
	//函数指针变量的写法
	//  用（*pf）替代Add，形参只保留类型
	
	//调用函数：可以用函数指针
	int ret = (*pf)(4, 9);
	int ret1 = (pf)(3, 4);
	int ret2 = pf(3, 4);
    //(*pf）替代Add
	printf("%d\n", ret);
	printf("%d\n", ret1);
	printf("%d\n", ret2);


}














































































































































































































